package top.wineye.spring.dependency.source;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;

@Configuration  // not necessary, make idea happy
public class InjectSource {
    /*
        在 Lookup 三种来源（BeanDefinition \
                          singletonBean \
                          default bean post processor ）的基础上
        新增加了 Resolvable Dependency
        非 Spring 容器管理对象，游离对象

        AbstractApplicationContext#prepareBeanFactory 中
        调用了
        ConfigurableListableBeanFactory#registerResolvableDependency
        注册了所谓的 Resolvable Dependency
                * Register a special dependency type with corresponding autowired value.
	            * <p>This is intended for factory/context references that are supposed
	            * to be autowire-able but are not defined as beans in the factory:
	            * e.g. a dependency of type ApplicationContext resolved to the
	            * ApplicationContext instance that the bean is living in.

	    该方法建立了一个 Class 类型和对象之间的映射
	    当进行 Autowired 注入， 查找候选对象的时候，会去查找这个映射 Map。

	    因此，依赖注入和依赖查找的来源是不一致的，也就是这些对象能够通过依赖注入注入，不能通过
	    beanFactory.getBean 获取。


	              来源         ｜ Spring 容器中的对象 ｜ 生命周期管理 ｜ 配置元信息 ｜    场景    ｜
	    -----------------------+-------------------+-------------+-----------+-------------
	    BeanDefinition                 yes.              yes.         yes.    lookup+inject

	    Registered Singleton           yes.              no.          no.     lookup+inject

	    Resolvable Dependency          no.               no.          no.      inject only
     */

    @Autowired
    ApplicationContext context;


    public static void main(String[] args) {

        AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(InjectSource.class);


        InjectSource bean = ctx.getBean(InjectSource.class);
        System.out.println(bean.context);
        System.out.println(bean.context == ctx);


        try {
            ApplicationContext tryGetApplicationContext = ctx.getBean(ApplicationContext.class);
            System.out.println(tryGetApplicationContext);
        } catch (NoSuchBeanDefinitionException e) {
            System.out.println("cannot get ApplicationContext from BeanFactory: " + e.getMessage());
        }

        ctx.close();

    }

}
